<?php
/**
 * @Notes:【】
 * @Date: 2022-06-03 15:58
 */

namespace Yj\Generator\Core\Common\Template;

use Krlove\CodeGenerator\Exception\ValidationException;
use Krlove\CodeGenerator\Model\ArgumentModel;
use Krlove\CodeGenerator\Model\BaseMethodModel;
use Krlove\CodeGenerator\Model\MethodModel;
use Krlove\CodeGenerator\Model\Traits\AbstractModifierTrait;
use Krlove\CodeGenerator\Model\Traits\AccessModifierTrait;

use Krlove\CodeGenerator\Model\Traits\FinalModifierTrait;
use Krlove\CodeGenerator\Model\Traits\StaticModifierTrait;
use Yj\Generator\Core\Common\RenderableTemplate;
use Yj\Generator\Core\Common\Template\Traits\AccessTrait;
use Yj\Generator\Core\Common\Template\Traits\DocBlockTrait;

class MethodTemplate extends RenderableTemplate
{
//    use AbstractModifierTrait;
    use AccessTrait;
    use DocBlockTrait;

//    use FinalModifierTrait;
//    use StaticModifierTrait;

    /**
     * @var string
     */
    protected $body;

    /**
     * @var string
     */
    protected $name;

    /**
     * @var ArgumentTemplate[]
     */
    protected $arguments = [];

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     *
     * @return $this
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @return ArgumentTemplate[]
     */
    public function getArguments()
    {
        return $this->arguments;
    }

    /**
     * @param ArgumentTemplate $argument
     *
     * @return $this
     */
    public function addArgument(ArgumentTemplate $argument)
    {
        $this->arguments[] = $argument;

        return $this;
    }

    /**
     * @return string
     */
    protected function renderArguments()
    {
        $result = '';
        if ($this->arguments) {
            $arguments = [];
            foreach ($this->arguments as $argument) {
                $arguments[] = $argument->render();
            }
            $result .= implode(', ', $arguments);
        }

        return $result;
    }

    /**
     * MethodModel constructor.
     * @param string $name
     * @param string $access
     */
    public function __construct($name, $access = 'public')
    {
        $this->setName($name)
            ->setAccess($access);
    }

    /**
     * {@inheritDoc}
     */
    public function toLines()
    {
        $lines = [];
        if ($this->docBlock !== null) {
            $lines = array_merge($lines, $this->docBlock->toLines());
        }

        $function = '';
//        if ($this->final) {
//            $function .= 'final ';
//        }
//        if ($this->abstract) {
//            $function .= 'abstract ';
//        }
        $function .= $this->access . ' ';
//        if ($this->static) {
//            $function .= 'static ';
//        }

        $function .= 'function ' . $this->name . '(' . $this->renderArguments() . ')';

//        if ($this->abstract) {
//            $function .= ';';
//        }


        $lines[] = $function;
//        if (!$this->abstract) {
        $lines[] = '{';
        if ($this->body) {
            $lines = array_merge($lines,$this->body);
//            $lines[] = sprintf('%s', $this->body); // TODO: make body renderable
        }
        $lines[] = '}';
//        }
        return $lines;
    }

    /**
     * @return string
     */
    public function getBody()
    {
        return $this->body;
    }

    /**
     * @param string $body
     *
     * @return $this
     */
    public function setBody($body)
    {
        $this->body = explode(PHP_EOL,$body);

        return $this;
    }

    /**
     * {@inheritDoc}
     */
    protected function validate()
    {
        if ($this->abstract and ($this->final or $this->static)) {
            throw new ValidationException('Entity cannot be abstract and final or static at the same time');
        }

        return parent::validate();
    }
}